﻿using System;
using System.Collections.Generic;

namespace Core
{
    public class World : IDisposable
    {
        public static World Main = new World(SceneType.Main);

        public Scene Root { get; }

        public EventSystem EventSystem { get; }

        private static Dictionary<long, Entity> components = new Dictionary<long, Entity>();

        internal World(SceneType sceneType)
        {
            EventSystem = new EventSystem();
            Root = new Scene(this, sceneType);
        }

        public void Update()
        {
            EventSystem.Update();
        }

        public void FixedUpdate()
        {
            EventSystem.FixedUpdate();
        }

        public static T GetComponent<T>() where T : Entity
        {
            components.TryGetValue(typeof(T).ToRuntimeId(), out var component);
            return component as T;
        }

        public static T AddComponent<T>() where T : Entity
        {
            var type = typeof(T);
            var typeId = type.ToRuntimeId();
            if (components.TryGetValue(typeId, out var component))
            {
                return component as T;
            }
            component = Activator.CreateInstance(type) as T;
            component.InstanceId = typeId;
            AwakeSystem.Awake(component);
            components[typeId] = component;
            component.Scene = Main.Root;
            
            return component as T;
        }

        public static T AddComponent<T, A>(A a) where T : Entity
        {
            var type = typeof(T);
            var typeId = type.ToRuntimeId();
            if (components.TryGetValue(typeId, out var component))
            {
                return component as T;
            }
            component = Activator.CreateInstance(type) as T;
            component.InstanceId = typeId;
            AwakeSystem.Awake(component, a);
            components[typeId] = component;
            component.Scene = Main.Root;
            return component as T;
        }

        public void Dispose()
        {
            Root?.Dispose();
            foreach (var component in components.Values)
            {
                component.Dispose();
            }
            components?.Clear();
            components = null;
        }
    }
}
